﻿using System.Collections.Generic;
using GameLibrary;
using Microsoft.Xna.Framework;
using Rescue_of_the_Dwarvenzombies.Scene;
using Rescue_of_the_Dwarvenzombies.SceneLayers;
using Rescue_of_the_Dwarvenzombies.SceneObjects.GameObjects.Items.NonConsumableItems;

namespace Rescue_of_the_Dwarvenzombies.SceneObjects.GameObjects.Characters
{
    internal class Player : Character
    {
        private Game _game;
        private PlayerIndex _playerIndex;
        private PlayerLayer _parentLayer;
        private float _timeSinceLastAttack;

        /// <summary>
        /// Initializes a new instance of the Player class.
        /// </summary>
        /// <param name="playerIndex">Index of the player.</param>
        /// <param name="game">The game.</param>
        /// <param name="parentLayer">The parent layer.</param>
        /// <param name="startPosition">The start position.</param>
        /// <param name="tintColor">Color of the tint.</param>
        public Player(PlayerIndex playerIndex, Game game, PlayerLayer parentLayer, Vector2 startPosition, Color tintColor)
        {
            _parentLayer = parentLayer;
            _playerIndex = playerIndex;
            _game = game;
            TintColor = tintColor;
            Position = startPosition;
            InitPlayer();
        }

        /// <summary>
        /// Inits the players attributes.
        /// </summary>
        private void InitPlayer()
        {
            TextureName = Constant.DWARF_TEXTURE_NAME;
            Velocity = 150;
            ThrowVelocity = 250;
            RateOfFire = 300;
            Damage = 50;
            _timeSinceLastAttack = RateOfFire;
            SourceRectangle = new Rectangle(0, 0, Constant.DWARF_RECTANGLE_WIDTH, Constant.DWARF_RECTANGLE_HEIGHT);
            RectangleHeight = Constant.DWARF_RECTANGLE_HEIGHT;
            RectangleWidth = Constant.DWARF_RECTANGLE_WIDTH;
            RectangleOffsetX = Constant.DWARF_RECTANGLE_OFFSET_X;
            RectangleOffsetY = Constant.DWARF_RECTANGLE_OFFSET_Y;
            TotalTextureWidth = Constant.DWARF_TOTAL_TEXTURE_WIDTH;
            Direction = Constant.Direction.Down;

            //Calculate bounding box (Z-coordinate is always 0)
            BoundingBox = new BoundingBox(new Vector3(Position.X, Position.Y, 0), new Vector3(Position.X + RectangleWidth, Position.Y + RectangleHeight, 0));
        }

        public override void Update(GameTime gameTime)
        {
            //Add elapsed time
            _timeSinceLastAttack += (float)gameTime.ElapsedGameTime.TotalMilliseconds;

            //Get the user input
            WantedAction = ((IInputManager)_game.Services.GetService(typeof(IInputManager))).CheckInput(_playerIndex);

            if (WantedAction == Constant.Action.DoNothing)
            {
                //Do nothing if no action found.
                WantedMove = new Vector2(0, 0);
                return;
            }


            if (WantedAction == Constant.Action.Attack)
            {
                //Check if enough time has passed to attack
                if (_timeSinceLastAttack >= RateOfFire)
                {
                    _timeSinceLastAttack = 0;
                    Attack();
                }
            }
            else
                Move();
        }

        /// <summary>
        /// Handles the attack command of the player
        /// </summary>
        public override void Attack()
        {
            //soundmanager uses the objectname and event to match the corresponding sound
            //should be in weaponmethod instead?

            ((ISoundManager)_game.Services.GetService(typeof(ISoundManager))).Play(this, Constant.Action.Attack);

            //USE player direction and attackspeed to calculate Vector2 of new weapon
            Vector2 throwDirection;
            Constant.Action wantedAction;
            WantedMove = new Vector2(0, 0);
            switch (Direction)
            {
                case Constant.Direction.Up:
                    throwDirection = Constant.Transitions.MoveUp;
                    wantedAction = Constant.Action.MoveUp;
                    break;
                case Constant.Direction.Down:
                    throwDirection = Constant.Transitions.MoveDown;
                    wantedAction = Constant.Action.MoveDown;
                    break;
                case Constant.Direction.Left:
                    throwDirection = Constant.Transitions.MoveLeft;
                    wantedAction = Constant.Action.MoveLeft;
                    break;
                case Constant.Direction.Right:
                    throwDirection = Constant.Transitions.MoveRight;
                    wantedAction = Constant.Action.MoveRight;
                    break;
                case Constant.Direction.DownLeft:
                    throwDirection = Constant.Transitions.MoveDownLeft;
                    wantedAction = Constant.Action.MoveDownLeft;
                    break;
                case Constant.Direction.DownRight:
                    throwDirection = Constant.Transitions.MoveDownRight;
                    wantedAction = Constant.Action.MoveDownRight;
                    break;
                case Constant.Direction.UpLeft:
                    throwDirection = Constant.Transitions.MoveUpLeft;
                    wantedAction = Constant.Action.MoveUpLeft;
                    break;
                case Constant.Direction.UpRight:
                    throwDirection = Constant.Transitions.MoveUpRight;
                    wantedAction = Constant.Action.MoveUpRight;
                    break;
                default:
                    throwDirection = Constant.Transitions.DoNothing;
                    wantedAction = Constant.Action.DoNothing;
                    return; //Do nothing if no move found
                //throw exception
            }

            //Create a new weapon with some of the player properties
            ((WeaponLayer)_parentLayer.Child).AddObject(new Weapon(throwDirection * ThrowVelocity, Direction, wantedAction,
                new Vector2(Position.X + (float)RectangleWidth * 0.25f, Position.Y + (float)RectangleHeight * 0.25f), Damage));
        }

        /// <summary>
        /// Handles the move command of the player
        /// </summary>
        public override void Move()
        {
            switch (WantedAction)
            {
                case Constant.Action.MoveUp:
                    WantedMove = Constant.Transitions.MoveUp;
                    Direction = Constant.Direction.Up;
                    break;
                case Constant.Action.MoveDown:
                    WantedMove = Constant.Transitions.MoveDown;
                    Direction = Constant.Direction.Down;
                    break;
                case Constant.Action.MoveLeft:
                    WantedMove = Constant.Transitions.MoveLeft;
                    Direction = Constant.Direction.Left;
                    break;
                case Constant.Action.MoveRight:
                    WantedMove = Constant.Transitions.MoveRight;
                    Direction = Constant.Direction.Right;
                    break;
                case Constant.Action.MoveDownLeft:
                    WantedMove = Constant.Transitions.MoveDownLeft;
                    Direction = Constant.Direction.DownLeft;
                    break;
                case Constant.Action.MoveDownRight:
                    WantedMove = Constant.Transitions.MoveDownRight;
                    Direction = Constant.Direction.DownRight;
                    break;
                case Constant.Action.MoveUpLeft:
                    WantedMove = Constant.Transitions.MoveUpLeft;
                    Direction = Constant.Direction.UpLeft;
                    break;
                case Constant.Action.MoveUpRight:
                    WantedMove = Constant.Transitions.MoveUpRight;
                    Direction = Constant.Direction.UpRight;
                    break;
            }
            WantedMove *= Velocity;
        }

        /// <summary>
        /// Takes the damage. Used if the players have split health
        /// </summary>
        /// <param name="damage">The damage.</param>
        public override void TakeDamage(float damage)
        {
            //This is done in PlayingState now that all players have same health/time
        }
    }
}